package Gestor;

import Clases.Asignardeduccion;
import Clases.Deduccion;
import Control.ControlPago;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.LogicalExpression;
import org.hibernate.criterion.Restrictions;

public class GestorDeduccion extends GestorBase {

    private static GestorDeduccion instancia = null;
    private static final String DEDUCCION_CEDULA = "SP_SELECCIONAR_DEDUCCIONES_POR_CEDULA";
    private static final String DEDUCCION_CODIGO = "SP_SELECCIONAR_DEDUCCIONES_POR_CODIGO";
    private static final String DEDUCCION_HISTORICOS = "SP_DEDUCCIONES_HISTORICOS";

    public static GestorDeduccion obtenerInstancia() {
        if (instancia == null) {
            instancia = new GestorDeduccion();
        }
        return instancia;
    }

    private GestorDeduccion() {

    }

    @Override
    public Object insertar(Object deduccion) {
        int exito = -1;//si solo retorna -1 entonces hubo un error
        try {
            iniciaOperacion();
            exito = (Integer) sesion.save(deduccion);
            tx.commit();

        } catch (HibernateException he) {
            System.out.println(he.getCause());
            System.out.println(he.getMessage());
            exito = -1;
            manejaExcepcion(he);
        } finally {
            sesion.close();
        }

        return exito;
    }

    //devuelve una lista de deducciones(con todos los atributos) donde los parametros, son los parametros
    //que se deben pasar al procedimiento almacena
    // y procedimiento es el nombre del procedimiento almacenado
    private ArrayList<Deduccion> getListaGenericaDeducciones(String procedimiento, ArrayList<Object> parametros) throws HibernateException {

        ArrayList<Deduccion> deducciones = new ArrayList<>();
        try {
            ResultSet rs = llamarProcedimientoAlmacenado(procedimiento, parametros);
            int maxCols = rs.getMetaData().getColumnCount();
            while (rs.next()) {
                ArrayList<Object> registro = new ArrayList<>(maxCols);
                for (int i = 0; i < maxCols; i++) {
                    registro.add(rs.getObject(i + 1));
                }
                deducciones.add(Deduccion.fromArray(registro));
            }

        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | SQLException e) {
            System.out.println(e.getMessage());
        } finally {
        }
        return deducciones;
    }

    public ArrayList<Deduccion> getDeduccionesPorCodigo(long codigo, Date fechaPagoInicio, Date fechaPagoFin) throws HibernateException {

        ArrayList<Object> parametros = new ArrayList<>();
        parametros.add(codigo);
        parametros.add(fechaPagoInicio);
        parametros.add(fechaPagoFin);
        return getListaGenericaDeducciones(DEDUCCION_CODIGO, parametros);
    }

    public ArrayList<Deduccion> getDeduccionesPorCedula(long cedula, Date fechaPagoInicio, Date fechaPagoFin) throws HibernateException {

        ArrayList<Object> parametros = new ArrayList<>();
        parametros.add(cedula);
        parametros.add(fechaPagoInicio);
        parametros.add(fechaPagoFin);
        return getListaGenericaDeducciones(DEDUCCION_CEDULA, parametros);
    }

    public ArrayList<Deduccion> getListaDeducciones() throws HibernateException {
        ArrayList<Deduccion> listaDeduccions = null;
        try {
            iniciaOperacion();
            listaDeduccions = (ArrayList<Deduccion>) sesion.createQuery("from Deduccion WHERE activa=true").list();
        } finally {
            sesion.close();
        }
        return listaDeduccions;
    }

    //me da las q todavia estan vigentes
    public ArrayList<Deduccion> getListaDeduccionsActuales() throws HibernateException {
        ArrayList<Deduccion> listaDeduccions = null;
        try {
            iniciaOperacion();
            listaDeduccions = (ArrayList<Deduccion>) sesion.createQuery("from Deduccion WHERE activa=true AND ((fechaFin is null AND permanente=1) OR (fechaFin > CURDATE() AND permanente=0))").list();
        } finally {
            sesion.close();
        }
        return listaDeduccions;
    }

    public Deduccion getDeduccionPorCodigo(int codigo) throws HibernateException {
        Deduccion deduccion = null;
        try {
            iniciaOperacion();
            deduccion = (Deduccion) sesion.get(Deduccion.class, codigo);
        } finally {
            sesion.close();
        }

        return deduccion;
    }

    public boolean hayOtraAsignacion(Asignardeduccion asignacion) {
        boolean hayOtraAsignacion = true;
        try {
            iniciaOperacion();

            long cantidad = ((java.math.BigInteger) (sesion.createSQLQuery("select count(*) from "
                    + "asignardeduccion where fechaPagoInicio=:fechaInicio "
                    + "and fechaPagoFin=:fechaFin and numEmpleado=:num "
                    + "and codigoDeduccion=:codigo")
                    .setDate("fechaFin", asignacion.getPago().getId()
                            .getFechaPagoFin()).setDate("fechaInicio",
                            asignacion.getPago().getId().getFechaPagoInicio())
                    .setParameter("num", asignacion.getPago().getId()
                            .getNumEmpleado()).setParameter("codigo", asignacion
                            .getDeduccion().getCodigo()).uniqueResult())).longValue();
            if (cantidad == 0) {
                hayOtraAsignacion = false;
            }
        } catch (HibernateException he) {
            System.out.println(he.getCause());
            System.out.println(he.getMessage());
        } finally {
            sesion.close();
        }
        return hayOtraAsignacion;

    }

    public long cantidadAsignaciones(int codigoDeduccion) {
        long cantidad = 1;
        try {
            iniciaOperacion();

            cantidad = ((java.math.BigInteger) (sesion.createSQLQuery("select count(*) from "
                    + "asignardeduccion where codigoDeduccion=:codigo")
                    .setParameter("codigo", codigoDeduccion)).uniqueResult()).longValue();

        } catch (HibernateException he) {
            System.out.println(he.getCause());
            System.out.println(he.getMessage());
        } finally {
            sesion.close();
        }
        return cantidad;

    }

    public boolean asignarDeduccion(Object asignarDeduccion) {
        boolean verifica = false;
        try {
            iniciaOperacion();
            /*Object verificaAsignacion = sesion.createQuery("from asignardeduccion where codigo= :?")
                    .setParameter("?", ((Asignardeduccion) asignarDeduccion).getDeduccion().getCodigo())
                    .uniqueResult();
            if (verificaAsignacion == null) {*/
                sesion.save(asignarDeduccion);
                tx.commit();
                verifica = true;
            /*} else {
                return false;//El codigo ya esta ocupado
            }*/
        } catch (HibernateException he) {
            System.out.println(he.getCause());
            System.out.println(he.getMessage());
            manejaExcepcion(he);
        } finally {
            sesion.close();
        }

        return verifica;
    }

    public ArrayList<Asignardeduccion> getAsignacionDeducciones(long numEmpleado) {
        ArrayList<Asignardeduccion> listaAsignaciones = null;
        try {
            iniciaOperacion();
            ArrayList<java.util.Date> fechas = ControlPago.obtenerInstancia().getPago();
            Criteria cr = sesion.createCriteria(Asignardeduccion.class);
            Criterion fechaInicio = Restrictions.eq("pago.id.fechaPagoInicio", fechas.get(0));
            Criterion fechaFin = Restrictions.eq("pago.id.fechaPagoFin", fechas.get(1));
            Criterion numeroEmpleado = Restrictions.eq("pago.id.numEmpleado", numEmpleado);
            LogicalExpression andExp = Restrictions.and(fechaInicio, fechaFin);
            cr.add(andExp);
            cr.add(numeroEmpleado);
            listaAsignaciones = (ArrayList<Asignardeduccion>) cr.list();
        } catch (HibernateException he) {
            System.out.println(he.getCause());
            System.out.println(he.getMessage());
        } finally {
            sesion.close();
        }
        return listaAsignaciones;

    }

    public ArrayList<Asignardeduccion> getAsignacionDeduccion(Asignardeduccion asignacion) {
        ArrayList<Asignardeduccion> asignacionD = new ArrayList<Asignardeduccion>();
        try {
            iniciaOperacion();
            /* asignacionD = (Asignardeduccion) sesion.createQuery("from asignardeduccion where codigoDeduccion=:cod and numEmpleado=:num and fechaPagoInicio=:inicio and fechaPagoFin=:fin")
             .setParameter("cod", asignacion.getDeduccion().getCodigo())
             .setParameter("num", asignacion.getPago().getEmpleado().getNumEmpleado())
             .setParameter("inicio", asignacion.getPago().getId().getFechaPagoInicio())
             .setParameter("fin", asignacion.getPago().getId().getFechaPagoFin())
             .uniqueResult();*/
            Criteria cr = sesion.createCriteria(Asignardeduccion.class);
            Criterion fechaInicio = Restrictions.eq("pago.id.fechaPagoInicio", ((Asignardeduccion) asignacion).getPago().getId().getFechaPagoInicio());
            Criterion fechaFin = Restrictions.eq("pago.id.fechaPagoFin", ((Asignardeduccion) asignacion).getPago().getId().getFechaPagoFin());
            Criterion numEmpleado = Restrictions.eq("pago.id.numEmpleado", ((Asignardeduccion) asignacion).getPago().getEmpleado().getNumEmpleado());
            Criterion codigoDeduccion = Restrictions.eq("deduccion.codigo", ((Asignardeduccion) asignacion).getDeduccion().getCodigo());
            LogicalExpression andExp = Restrictions.and(fechaInicio, fechaFin);
            cr.add(andExp);
            cr.add(codigoDeduccion);
            cr.add(numEmpleado);
            asignacionD = (ArrayList<Asignardeduccion>) cr.list();

        } catch (HibernateException he) {
            System.out.println(he.getCause());
            System.out.println(he.getMessage());
        } finally {
            sesion.close();
        }
        return asignacionD;

    }

    public ArrayList<Asignardeduccion> getListaAsignacionesActualesPorDeduccion(int codigoDeduccion) {
        ArrayList<Asignardeduccion> listaAsignaciones = null;
        try {
            ArrayList<java.util.Date> fechas = ControlPago.obtenerInstancia().getPago();
            iniciaOperacion();
            Criteria cr = sesion.createCriteria(Asignardeduccion.class);
            Criterion fechaInicio = Restrictions.eq("pago.id.fechaPagoInicio", fechas.get(0));
            Criterion fechaFin = Restrictions.eq("pago.id.fechaPagoFin", fechas.get(1));
            Criterion codigo = Restrictions.eq("deduccion.codigo", codigoDeduccion);
            LogicalExpression andExp = Restrictions.and(fechaInicio, fechaFin);
            cr.add(andExp);
            cr.add(codigo);
            listaAsignaciones = (ArrayList<Asignardeduccion>) cr.list();

        } catch (HibernateException he) {
            System.out.println(he.getCause());
            System.out.println(he.getMessage());
            manejaExcepcion(he);
        } finally {
            sesion.close();
        }
        return listaAsignaciones;
    }

    public ArrayList<Asignardeduccion> getListaAsignacionesPorDeduccion(int codigoDeduccion) {
        ArrayList<Asignardeduccion> listaAsignaciones = null;
        try {
            iniciaOperacion();
            Criteria cr = sesion.createCriteria(Asignardeduccion.class);
            Criterion fechaInicio = Restrictions.eq("codigo", codigoDeduccion);
            /*listaAsignaciones = (ArrayList<Asignardeduccion>) sesion.createSQLQuery("select * from asignardeduccion where codigoDeduccion=:codigo")
                    .setParameter("codigo", codigoDeduccion)
                    .list();*/
            listaAsignaciones= (ArrayList<Asignardeduccion>) cr.list();
        } finally {
            sesion.close();
        }
        return listaAsignaciones;
    }

    public ArrayList<Deduccion> getAsignacionDeduccionesHistoricos(Long numEmpleado, Date fechaPagoInicio, Date fechaPagoFin) {
        ArrayList<Object> parametros = new ArrayList<>();
        parametros.add(numEmpleado);
        parametros.add(fechaPagoInicio);
        parametros.add(fechaPagoFin);
        return getListaGenericaDeducciones(DEDUCCION_HISTORICOS, parametros);

    }
}
